/******************************************************************************* 
  Copyright (C), 1988-2020, zeno Tech. Co., Ltd.
  Description:   VIDEO模块  
  Function List:     
  History:
    <wyg -- 2022-10-18>  创建
*******************************************************************************/ 

/*=============================================================================
                                 Includes                                  
 =============================================================================*/
#include "videoPriv.h"
#include "videoIsp.h"
#include "StreamComposeMgr.h"


/*=============================================================================
                               Macro Definition
 =============================================================================*/

#define DEC_CALL_BACK
#define DEC_WIDTH 1920
#define DEC_HEIGHT 1080


/*=============================================================================
                        Local Structures and Typedef 
 =============================================================================*/


/*=============================================================================
                             Extern Variables                                  
=============================================================================*/

/*=============================================================================
                             Local Variables                                  
 =============================================================================*/
static pthread_t    decGetDataThd;
static int hasCreated_s = 0;

/*=============================================================================
                             Function Definition                                  
 =============================================================================*/ 

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
//保存文件到pathname，O_TRUNC表示打开已存在的文件，并清除文件
//len = 0;为关闭文件，使用如:FILE_write("/root/test.dav", pData, dataLen);
int FILE_write(char *pathname, char *buf, int len) 
{
    static int fd = -1;
    int ret = 0;

    if (fd < 0)
    {
        fd = open(pathname, O_RDWR | O_CREAT | O_TRUNC, 0666);
        if (fd < 0)
        {
            printf("err: open %s fail, try again!\n", pathname);
            return -1;
        }
    }

    if (len == 0)
    {
        close(fd);
        fd = -1;
        printf("close %s\n", pathname);
        return 0;
    }

    ret = write(fd, buf, len);
    if (ret <= 0)
    {
        printf("err: write %s fail\n", pathname);
        return -1;
    }
    return 0;
}

static __attribute__((noinline)) void neon_memcpy2(volatile unsigned char *dst, volatile unsigned char *src, int sz)
{
    if (sz & 63)
        sz = (sz & -64) + 64;
    asm volatile(
    "NEONCopyPLD2: \n"
            " PLD  [%[src], #0xC0] \n"
            " VLDM %[src]!,{d0-d7} \n"
            " VSTM %[dst]!,{d0-d7} \n"
            " SUBS %[sz],%[sz],#0x40 \n"
            " BGT NEONCopyPLD2 \n"
    : [dst]"+r"(dst), [src]"+r"(src), [sz]"+r"(sz) : : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "cc", "memory");
}

static void Change_RectSize(ENC_ImageRect_t* rect, int srcH, int srcW) {
    float showScreen = (DEC_HEIGHT * 1.0) / DEC_WIDTH;
    float videoScreen = (srcH * 1.0) / srcW;
    int midWei = 0;
    int widSub = 0;
    int isEven = 0;
    float midFloatWid = 0.0;
    if (showScreen > videoScreen) {
        if (srcW <= DEC_WIDTH) {
            widSub = DEC_WIDTH - srcW;
        }

        rect->wid = DEC_WIDTH;
        rect->wstride = DEC_WIDTH;
        if (srcH <= DEC_HEIGHT) {
            midFloatWid = (widSub * 1.0) / srcW;
            midWei = midFloatWid * srcH;
            isEven = midWei % 2;
            midWei -= isEven;
            midWei += srcH;
            if (midWei <= DEC_HEIGHT) {
                rect->hei = midWei;
                rect->hstride = midWei;
            }
            else
            {
                rect->hei = DEC_HEIGHT;
                rect->hstride = DEC_HEIGHT;
            }
        }
        else {
            rect->hei = DEC_HEIGHT;
            rect->hstride = DEC_HEIGHT;
        }
    }
    else 
    {
        if (srcH <= DEC_HEIGHT) {
            widSub = DEC_HEIGHT - srcH;
        }

        rect->hei = DEC_HEIGHT;
        rect->hstride = DEC_HEIGHT;
        if (srcW < DEC_WIDTH) {
            midFloatWid = (widSub * 1.0) / srcH;
            midWei = midFloatWid * srcW;
            isEven = midWei % 2;
            midWei -= isEven;
            midWei += srcW;

            if (midWei <= DEC_WIDTH) {
                rect->wid = midWei;
                rect->wstride = midWei;
            }
            else
            {
                rect->wid = DEC_WIDTH;
                rect->wstride = DEC_WIDTH;
            }
        }
        else
        {
            rect->wid = DEC_WIDTH;
            rect->wstride = DEC_WIDTH;
        }
    }
    //LOG_PrintError("midWei : %d isEven:%d midFloatWid:%f srcw: %d srch:%d widSub :%d midFloatWid :%f\n"
       // , midWei, isEven, midFloatWid, srcW, srcH, widSub, midFloatWid);
}

/*static int video_FILE_Write(char *pathname, char *buf, int len) 
{
    static int fd = -1;
    int ret = 0;

    if (fd < 0)
    {
        fd = open(pathname, O_RDWR | O_CREAT | O_TRUNC, 0666);
        if (fd < 0)
        {
            printf("err: open %s fail, try again!\n", pathname);
            return -1;
        }
    }

    if (len == 0)
    {
        close(fd);
        fd = -1;
        printf("close %s\n", pathname);
        return 0;
    }

    ret = write(fd, buf, len);
    if (ret <= 0)
    {
        printf("err: write %s fail\n", pathname);
        return -1;
    }
    return 0;
}*/

static void DEC_PacketCb(MEDIA_BUFFER mb) 
{
    if (!mb)
    {
        LOG_PrintError("DEC_PacketCb mb is NULL\n");
        return;
    }
    
    STREAM_composeCtl_t* pComposeCtl = videoCtl_g.pComposeCtl;
    if (!pComposeCtl)
    {
        LOG_PrintInfo("pComposeCtl is NULL\n");
        return;
    }
    
    DEC_ctl_t *pDecCtl;
    int bufLen = 0;
    unsigned short chnId = 0;     
    MEDIA_BUFFER srcMd = mb;
    size_t decLen = 0;
    COMM_ListInfo_t *pListFrame = NULL;
    CurtainInfo curtainInfo = {0};
    StreamCofigInfo configInfo = {0};
    VideoMixerInfo videoMixerInfo = {0};
    StreamInfo stream = {0};
    ScreenCodt codt = {0}; 
    int outNum = 0;
    int pictureNum = 0;
    int vdecChn = 0;
    int dealNum = 0;
    ENC_ImageRect_t stSrcRect = {0};
    ENC_ImageRect_t stDstRect = {0};
    unsigned long long ts = 0;
    static long long cnt_tmp = 0;
    static uint64_t lastPts_s = 0;

    RK_U64 pts = RK_MPI_MB_GetTimestamp(mb);
    chnId = RK_MPI_MB_GetChannelID(mb);
 
     if (RK_MPI_MB_GetModeID(mb) == RK_ID_VDEC) 
     {
         if (chnId >= (VDEC_MAX_CHN_NUM))
         {
             LOG_PrintError("chnId(%d) is invalid.\n", chnId);
             goto release_buf;
         }
         pDecCtl = videoCtl_g.pDecCtls[chnId];
         if (!pDecCtl)
         {
             LOG_PrintError("pDecCtl is NULL\n");
             goto release_buf;
         }
         
         vdecChn = pDecCtl->vdecChn;
         bufLen = RK_MPI_MB_GetSize(mb);
 
         if (bufLen > pDecCtl->maxBufLen || bufLen <= 0 || pDecCtl->decState == DEC_STOP)
         {
             LOG_PrintError("VDEC channel:%d, bufLen is invalid,(%d, %d), decState:%d\n",chnId, bufLen, pDecCtl->maxBufLen, pDecCtl->decState);
             goto release_buf;
         }

        MB_IMAGE_INFO_S stImageInfo = {0};
        int ret = RK_MPI_MB_GetImageInfo(mb, &stImageInfo);
        if (ret) 
        {
            printf("Get image info failed! ret = %d\n", ret);
            RK_MPI_MB_ReleaseBuffer(mb);
            return ;
        }

        if(pDecCtl->vdecAttr.enCodecType == RK_CODEC_TYPE_JPEG)
        {
            pthread_mutex_lock(&pDecCtl->frameLock);  
            // 生产数据（这里只是简单地增加shared_data）  
            pDecCtl->frameComeflg = 1;
            // 通知消费者条件已成立  
            pthread_cond_signal(&pDecCtl->frameCond);  
      
            pthread_mutex_unlock(&pDecCtl->frameLock);  
        }
#if 0
        if(cnt_tmp++ % 30 == 0)
        LOG_PrintWarn("DEC_PacketCb vdecChn:%d,ImgInfo:<wxh %dx%d, fmt 0x%x>, HorStride:%d, VerStride:%d, size:%u\n",
                         pDecCtl->vdecChn, stImageInfo.u32Width,
                         stImageInfo.u32Height, stImageInfo.enImgType,
                         stImageInfo.u32HorStride,
                         stImageInfo.u32VerStride,
                         RK_MPI_MB_GetSize(mb));
        goto release_buf;

#endif         
        uint16_t srcEncType = RK_FORMAT_YCbCr_420_SP;
        if(stImageInfo.enImgType == IMAGE_TYPE_NV12)
        {
            srcEncType = RK_FORMAT_YCbCr_420_SP;
        }
        else if(stImageInfo.enImgType == IMAGE_TYPE_NV16)
        {
            srcEncType = RK_FORMAT_YCbCr_422_SP;
        }
        
        ///getlist -- getbuffer -- buffer deal -- setlist
        pthread_mutex_lock(&pDecCtl->bufLock);
        if(!list_empty(&pDecCtl->emptyBuf))
        {
            pListFrame = list_first_entry(&pDecCtl->emptyBuf, COMM_ListInfo_t, list);
            list_del(&pListFrame->list);
            pthread_mutex_unlock(&pDecCtl->bufLock);

            //LOG_PrintWarn("emptyBuf list is get!,vdecChn=%d\n",vdecChn);
        }
        else
        {
            if (!list_empty(&pDecCtl->fullBuf)) {
                pListFrame = list_first_entry(&pDecCtl->fullBuf, COMM_ListInfo_t, list);
                list_del(&pListFrame->list);
                list_add_tail(&pListFrame->list, &pDecCtl->emptyBuf);
                pListFrame = list_first_entry(&pDecCtl->emptyBuf, COMM_ListInfo_t, list);
                list_del(&pListFrame->list);
                pthread_mutex_unlock(&pDecCtl->bufLock);
            }
            else 
            {
                pthread_mutex_unlock(&pDecCtl->bufLock);
                //LOG_PrintWarn("2 vdecChn:%d emptyBuf list is empty!\n", vdecChn);
                goto release_buf;
            } 
        }

        
        getCurtainLayout(&curtainInfo); //获取拼接布局
        outNum = curtainInfo.outNum;
        if(outNum <= 0)
        {
            LOG_PrintWarn("outNum <= 0!\n");
            goto release_buf;
        }

        dealNum = 0;
        for(int i = 0; i < outNum; ++i)
        {
            configInfo = curtainInfo.cofigInfo[i];
            
            videoMixerInfo = configInfo.videoMixerInfo;

            for(int j = 0; j < videoMixerInfo.totalPictures; ++j)
            {
                stream = videoMixerInfo.videoInfo[j].videoStream;
                StreamInType type = stream.type;
                codt = videoMixerInfo.videoInfo[j].codt;

                if(stream.displayChn == vdecChn) //解码通道和布局匹配
                {  
                    int srcW = stImageInfo.u32Width;
                    int srcH = stImageInfo.u32Height;

                    int pictureW = codt.width;
                    int pictureH = codt.height;
                    stDstRect.wid = pictureW;
                    stDstRect.hei = pictureH;

                    if(pictureW == 0 || pictureH == 0)
                    {
                        continue;
                    }
                                                    
                    /*pListFrame->mdBuf = srcMd;                             
                    if(pictureW == srcW && pictureH == srcH) //判断分辨率是否一致
                    {                               
                        pListFrame->isNocopy = 1; //nocopy

                                                stDstRect.wstride = stImageInfo.u32HorStride;//使用实际图片的虚宽和虚高
                        stDstRect.hstride = stImageInfo.u32VerStride;
                    }
                    else*/
                    {
                        pListFrame->isNocopy = 0; 
                        if (videoMixerInfo.totalPictures == 1 &&
                            (type == ONLINEMP4_STREAM || type == MIRROR_STREAM) || type == VIDEOFILE_STREAM) 
                        {
                            Change_RectSize(&stDstRect, srcH, srcW);
                        }
                        else 
                        {
                            stDstRect.wstride = stDstRect.wid;//使用目标的宽和高
                            stDstRect.hstride = stDstRect.hei;
                        }
                        
                        /* resize,大于1路时，若展示分辨率一致，后续可以复用,否则拼接处再resize*/
                        stSrcRect.wid = srcW;
                        stSrcRect.hei = srcH;
                        stSrcRect.wstride = stImageInfo.u32HorStride;
                        stSrcRect.hstride = stImageInfo.u32VerStride;
                        
                        // uint64_t t1 = vdo_get_time();
                        if(VI_ImageResizeRga(stSrcRect, stDstRect, srcMd, pListFrame->mdResizeBuf, srcEncType, RK_FORMAT_YCbCr_420_SP) < 0)
                        {
                            LOG_PrintError("VI_ImageResizeRga failed !\n"); 
                            break;
                        }
                        // if(pDecCtl->vdecAttr.enCodecType == RK_CODEC_TYPE_JPEG){
                        //     printf("VI_ImageResizeRga  time %llu\n", vdo_get_time() - t1);
                        // }
                        
                    }

                    
                    pListFrame->stImageInfo = stDstRect;                                
                    pListFrame->streamType = stream.type;

                    if(pDecCtl->vdecAttr.enCodecType == RK_CODEC_TYPE_JPEG){
                        pListFrame->pts = pts;
                    }else{
                        pListFrame->pts = vdo_get_time();
                    }

                    if((pListFrame->pts <= lastPts_s) && (lastPts_s > 0))
                    {
                        pListFrame->pts = lastPts_s + 1;
                    }
                    lastPts_s = pListFrame->pts;

                    dealNum++;
                    break; //找到一路即返回
                }
            }
            
            if(dealNum > 0) //找到一路即返回
            break;
        }    

        if(dealNum == 0) //当前解码通道的流无需拼接
        {
            //LOG_PrintWarn("dealNum <= 0!\n");
            if(pListFrame)
            {
                ///put node to empty list
                pthread_mutex_lock(&pDecCtl->bufLock); 
                list_add_tail(&pListFrame->list, &pDecCtl->emptyBuf);
                pthread_mutex_unlock(&pDecCtl->bufLock);
            }
            goto release_buf;
        }   

        ///put node to full list
        pthread_mutex_lock(&pDecCtl->bufLock);
        list_add_tail(&pListFrame->list, &pDecCtl->fullBuf);
        pthread_mutex_unlock(&pDecCtl->bufLock);
#if 0
		static int is_first = 0;
		if(!is_first){
			LOG_PrintWarn("DEC_PacketCb vdecChn:%d,ImgInfo:<wxh %dx%d, fmt 0x%x>, HorStride:%d, VerStride:%d, size:%u\n",
                         pDecCtl->vdecChn, stImageInfo.u32Width,
                         stImageInfo.u32Height, stImageInfo.enImgType,
                         stImageInfo.u32HorStride,
                         stImageInfo.u32VerStride,
                         RK_MPI_MB_GetSize(mb));
			video_FILE_Write("/extern/decout.yuv", RK_MPI_MB_GetPtr(mb),bufLen);
			is_first = 1;
		}
#endif
        pComposeCtl->newPts[vdecChn] = pListFrame->pts; //更新buf时间

    #if 0
        //unsigned long long  runtime = vdo_get_time();// - ts;
        //printf("Compose_DataComposeThd::dealPacket runtime=%llu\n",runtime);
    

        if(vdecChn == 0) // && vdecChn == 0 //cnt_tmp++ % 1 == 0 && 
        {
            video_FILE_Write("/extern/decout.yuv", RK_MPI_MB_GetPtr(pListFrame->mdResizeBuf),bufLen);  
            
            //LOG_PrintWarn("vdecChn:%d, Test GetData! pListFrame->pts=%llu\n",vdecChn, pListFrame->pts);

            cnt_tmp++;
            printf("DEC_PacketCb::cnt_tmp2 = %lld, bufLen=%d\n", cnt_tmp, bufLen);

        }
    #endif

    }
 
 release_buf:
     RK_MPI_MB_ReleaseBuffer(mb);
     pListFrame = NULL;
 
     return;
}
 
static void *DEC_GetDataThd(void *parg)
{
    DEC_ctl_t *pDecCtl = (DEC_ctl_t *)parg;
    if (!pDecCtl)
    {
        LOG_PrintInfo("pDecCtl is NULL\n");
        return NULL;
    }

    STREAM_composeCtl_t* pComposeCtl = videoCtl_g.pComposeCtl;
    if (!pComposeCtl)
    {
        LOG_PrintInfo("pComposeCtl is NULL\n");
        return NULL;
    }

    prctl(PR_SET_NAME, __func__);
    LOG_PrintInfo("DEC_GetDataThd  tid:%d\n", gettid());

    MEDIA_BUFFER srcMd;
    size_t decLen = 0;
    COMM_ListInfo_t *pListFrame;
    CurtainInfo curtainInfo = {0};
    StreamCofigInfo configInfo = {0};
    VideoMixerInfo videoMixerInfo = {0};
    StreamInfo stream = {0};
    ScreenCodt codt = {0}; 
    int outNum = 0;
    int pictureNum = 0;
    int vdecChn = pDecCtl->vdecChn;
    int dealNum = 0;
    ENC_ImageRect_t stSrcRect = {0};
    ENC_ImageRect_t stDstRect = {0};

    unsigned long long ts = 0;

    long long cnt_tmp = 0;

    static uint64_t lastPts_s = 0;

    while(1)
    {      
        do
        {                
            if(pDecCtl->decState == DEC_START)
            {
                srcMd = RK_MPI_SYS_GetMediaBuffer(RK_ID_VDEC, vdecChn, -1); //获取解码数据,阻塞
                if (srcMd) 
                { 
                    /*ts = vdo_get_time();*/
                    
                    decLen = RK_MPI_MB_GetSize(srcMd);
                    if(decLen == 0)
                    {
                        RK_MPI_MB_ReleaseBuffer(srcMd);
                        //LOG_PrintWarn("TEST PRINT!\n");
                        continue;
                    }

                    if(pDecCtl->vdecAttr.enCodecType == RK_CODEC_TYPE_JPEG)
                    {
                        pthread_mutex_lock(&pDecCtl->frameLock);  
                        // 生产数据（这里只是简单地增加shared_data）  
                        pDecCtl->frameComeflg = 1;
                        // 通知消费者条件已成立  
                        pthread_cond_signal(&pDecCtl->frameCond);  
                  
                        pthread_mutex_unlock(&pDecCtl->frameLock);  
                    }

                    MB_IMAGE_INFO_S stImageInfo = {0};
                    RK_MPI_MB_GetImageInfo(srcMd, &stImageInfo);

                    
                    if(cnt_tmp++ % 30 == 0)                    
                    LOG_PrintWarn("RK_MPI_SYS_GetMediaBuffer vdecChn:%d,ImgInfo:<wxh %dx%d, fmt 0x%x>, HorStride:%d, VerStride:%d, size:%u\n",
                         pDecCtl->vdecChn, stImageInfo.u32Width,
                         stImageInfo.u32Height, stImageInfo.enImgType,
                         stImageInfo.u32HorStride,
                         stImageInfo.u32VerStride,
                         RK_MPI_MB_GetSize(srcMd));

                         
               #if 0   
                    ///test                   
                    //FILE_write("wyg/video/mjpgdec.yuv", RK_MPI_MB_GetPtr(srcMd), RK_MPI_MB_GetSize(srcMd)); 
                    RK_MPI_MB_ReleaseBuffer(srcMd);
                    //LOG_PrintWarn("TEST PRINT!\n");
                    continue;
               #endif  
               
                    ///getlist -- getbuffer -- buffer deal -- setlist
                    pthread_mutex_lock(&pDecCtl->bufLock);
                    if(!list_empty(&pDecCtl->emptyBuf))
                    {
                        pListFrame = list_first_entry(&pDecCtl->emptyBuf, COMM_ListInfo_t, list);
                        list_del(&pListFrame->list);
                        pthread_mutex_unlock(&pDecCtl->bufLock);

                        //LOG_PrintWarn("emptyBuf list is get!,vdecChn=%d\n",vdecChn);
                    }
                    else
                    {
                        pthread_mutex_unlock(&pDecCtl->bufLock);
                        LOG_PrintWarn("emptyBuf list is empty!\n");
                        RK_MPI_MB_ReleaseBuffer(srcMd);
                        continue;
                    }

                    
                    getCurtainLayout(&curtainInfo); //获取拼接布局
                    outNum = curtainInfo.outNum;
                    if(outNum <= 0)
                    {
                        RK_MPI_MB_ReleaseBuffer(srcMd);
                        LOG_PrintWarn("outNum <= 0!\n");
                        continue;
                    }
                                 

                    dealNum = 0;
                    for(int i = 0; i < outNum; ++i)
                    {
                        configInfo = curtainInfo.cofigInfo[i];
                        
                        videoMixerInfo = configInfo.videoMixerInfo;

                        for(int j = 0; j < videoMixerInfo.totalPictures; ++j)
                        {
                            stream = videoMixerInfo.videoInfo[j].videoStream;
                            codt = videoMixerInfo.videoInfo[j].codt;

                            if(stream.displayChn == vdecChn) //解码通道和布局匹配
                            {  
                                int srcW = stImageInfo.u32Width;
                                int srcH = stImageInfo.u32Height;

                                int pictureW = codt.width;
                                int pictureH = codt.height;
                                stDstRect.wid = pictureW;
                                stDstRect.hei = pictureH;
                                                                
                                /*pListFrame->mdBuf = srcMd;                             
                                if(pictureW == srcW && pictureH == srcH) //判断分辨率是否一致
                                {                               
                                    pListFrame->isNocopy = 1; //nocopy

                                    stDstRect.wstride = stImageInfo.u32HorStride;//使用实际图片的虚宽和虚高
                                    stDstRect.hstride = stImageInfo.u32VerStride;
                                }
                                else*/
                                {
                                    pListFrame->isNocopy = 0; 

                                    stDstRect.wstride = stDstRect.wid;//使用目标的宽和高
                                    stDstRect.hstride = stDstRect.hei;
                                    
                                    /* resize,大于1路时，若展示分辨率一致，后续可以复用,否则拼接处再resize*/
                                    stSrcRect.wid = srcW;
                                    stSrcRect.hei = srcH;
                                    stSrcRect.wstride = stImageInfo.u32HorStride;
                                    stSrcRect.hstride = stImageInfo.u32VerStride;

                                    if(VI_ImageResizeRga(stSrcRect, stDstRect, srcMd, pListFrame->mdResizeBuf, RK_FORMAT_YCbCr_420_SP, RK_FORMAT_YCbCr_420_SP) < 0)
                                    {
                                        LOG_PrintError("VI_ImageResizeRga failed !\n"); 
                                        break;
                                    }

                                    //FILE_write("wyg/dec1.yuv", RK_MPI_MB_GetPtr(pListFrame->mdResizeBuf), stDstRect.wid*stDstRect.hei*3/2);    
                                }

                                
                                pListFrame->stImageInfo = stDstRect;                                
                                pListFrame->streamType = stream.type;
                                // printf(" use vdo_get_time  to set pts");
                                pListFrame->pts = vdo_get_time();

                                dealNum++;
                                break; //找到一路即返回
                            }
                        }
                        
                        if(dealNum > 0) //找到一路即返回
                        break;
                    }    

                    if(dealNum == 0) //当前解码通道的流无需拼接
                    {
                        RK_MPI_MB_ReleaseBuffer(srcMd);
                        LOG_PrintWarn("dealNum <= 0!\n");
                        continue;
                    }
                    break;
               }
               usleep(10*1000);
           }
           else
           {
               usleep(10*1000);
           }
        }while(1);


        pthread_mutex_lock(&pDecCtl->bufLock);
        list_add_tail(&pListFrame->list, &pDecCtl->fullBuf);
        pthread_mutex_unlock(&pDecCtl->bufLock);

        pComposeCtl->newPts[vdecChn] = pListFrame->pts; //更新buf时间

        RK_MPI_MB_ReleaseBuffer(srcMd);

    #if 0
        //unsigned long long  runtime = vdo_get_time() - ts;
        //printf("Compose_DataComposeThd::dealPacket runtime=%llu\n",runtime);
    

        if(cnt_tmp++ % 1 == 0)
        LOG_PrintWarn("vdecChn:%d, Test GetData!\n",vdecChn);
    #endif
   }

   return NULL;

}


static int DEC_DeinitList(DEC_ctl_t *pDecCtl)
{
    COMM_ListInfo_t*pListFrame;
    
    while (!list_empty(&pDecCtl->fullBuf))
    {
        pListFrame = list_first_entry(&pDecCtl->fullBuf, COMM_ListInfo_t, list);
        list_del(&pListFrame->list);
        list_add_tail(&pListFrame->list, &pDecCtl->emptyBuf);
    }

    STREAM_composeCtl_t* pComposeCtl = videoCtl_g.pComposeCtl;
    if (!pComposeCtl)
    {
        LOG_PrintInfo("pComposeCtl is NULL\n");
        return -1;
    }

    int vdecChn = pDecCtl->vdecChn;
    pComposeCtl->newPts[vdecChn] = 0;      

    LOG_PrintWarn("DEC_DeinitList success vdecChn:%d\n", vdecChn);
    return 0;
}

 /*******************************************************************************
   Function:     DEC_SetFormat
   Description:  设置视频编码数据压缩的格式
   Input:        - pThiz: 视频编码接口指针
                 - pFormat 指向视频格式结构VideoDecFormat的指针，
                           NULL表示不编码视频。
   Output:       无
   Return:       0: 操作成功
                 -1: 操作失败
   Others:       无
 *******************************************************************************/
 static int DEC_SetFormat(struct VideoDecoder *pThiz, VideoDecFormat *pFormat)
 {
     int ret = 0;
     DEC_ctl_t *pDecCtl;
     VDEC_CHN_ATTR_S vencAttr;
     unsigned int viFrameRate;
     VIDEO_picSize_t picSize; 
     int statTime = 2;
     
     if (!pThiz || !pFormat)
     {
         LOG_PrintError("Input parameter is NULL\n");
         return -1;
     }
 
     pDecCtl = (DEC_ctl_t *)pThiz->priv;
     if (!pDecCtl)
     {
         LOG_PrintError("VideoDecoder isn't initialized\n");
         return -1;
     }
    
     pthread_mutex_lock(&videoCtl_g.decodeMutex[pDecCtl->vdecChn]);
 
     if (pDecCtl->decState != DEC_STOP)
     {
         LOG_PrintError("vdec channel %d is running!\n", pDecCtl->vdecChn);
         ret = -1;
         goto mutex_unlock;
     }
 
    
     pDecCtl->isCreateVdec = 1;

     memset(&vencAttr, 0, sizeof(vencAttr));

     vencAttr.enDecodecMode = VIDEO_DECODEC_HADRWARE;
 
     switch (pFormat->type)
     {
        case videoEncH264:
        case videoEncH264_Improve:
            vencAttr.enCodecType = RK_CODEC_TYPE_H264;             
            vencAttr.enMode = VIDEO_MODE_STREAM;
            break;
             
        case videoEncH265:
        case videoEncH265_Improve:
            vencAttr.enCodecType = RK_CODEC_TYPE_H265;             
            vencAttr.enMode = VIDEO_MODE_STREAM;
            break;
 
        case videoEncMotionJPEG:        
            vencAttr.enCodecType = RK_CODEC_TYPE_JPEG; //RK_CODEC_TYPE_MJPEG
            vencAttr.enMode = VIDEO_MODE_FRAME;
            break;
             
        case videoYuv420: 
            pDecCtl->isCreateVdec = 0;
            break;
            
        default:
             LOG_PrintError("stream type %d is unknow!\n", pFormat->type);
             ret =  -1;
             goto mutex_unlock;
     };
 
     memcpy(&pDecCtl->vdecAttr, &vencAttr, sizeof(VDEC_CHN_ATTR_S));

     LOG_PrintInfo("vdec channel %d DEC_SetFormat:%d success\n", pDecCtl->vdecChn, pFormat->type);

 mutex_unlock:  
     pthread_mutex_unlock(&videoCtl_g.decodeMutex[pDecCtl->vdecChn]);
     return ret;
 }


 /*******************************************************************************
  Function:     DEC_AddRef
  Description:  增加接口引用
  Input:        - pThiz: 视频解码接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int DEC_AddRef(struct VideoDecoder *pThiz)
{
    DEC_ctl_t *pDecCtl;

    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pDecCtl = (DEC_ctl_t *)pThiz->priv;
    if (!pDecCtl)
    {
        LOG_PrintError("VideoDecoder isn't initialized\n");
        return -1;
    }
        
    pthread_mutex_lock(&videoCtl_g.decodeMutex[pDecCtl->vdecChn]);

    pDecCtl->refCount++;
    
    pthread_mutex_unlock(&videoCtl_g.decodeMutex[pDecCtl->vdecChn]);
    
    return 0;
}
 /*******************************************************************************
   Function:     DEC_Release
   Description:  释放接口
   Input:        - pThiz: 视频解码接口指针
   Output:       无
   Return:       0: 操作成功
                 -1: 操作失败
   Others:       无
 *******************************************************************************/
 static int DEC_Release(struct VideoDecoder *pThiz)
 {
     int ret = 0;
     DEC_ctl_t *pDecCtl;
     
     if (!pThiz)
     {
         LOG_PrintError("Input parameter is NULL\n");
         return -1;
     }
 
     pDecCtl = (DEC_ctl_t *)pThiz->priv;
     if (!pDecCtl)
     {
         LOG_PrintError("VideoDecoder isn't initialized\n");
         return -1;
     }
     
     pthread_mutex_lock(&videoCtl_g.decodeMutex[pDecCtl->vdecChn]);
     
     if (pDecCtl->refCount > 1)
     {
         pDecCtl->refCount--;
         goto unlock_mutex;
     }
     
     videoCtl_g.pDecCtls[pDecCtl->vdecChn] = NULL;
     free(pDecCtl);
     
 unlock_mutex:       
     pthread_mutex_unlock(&videoCtl_g.decodeMutex[pDecCtl->vdecChn]);
     return ret;
 }

 /*******************************************************************************
  Function:     DEC_StartUnlock
  Description:  启动解码,不加锁
  Input:        - pDecCtl: 编码通道控制结构体 
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int DEC_StartUnlock(DEC_ctl_t *pDecCtl)
{
    int ret;
    MPP_CHN_S stDecChn;
    MOD_ID_E enModId;

    LOG_PrintWarn("pDecCtl->vdecChn:%d\n", pDecCtl->vdecChn);
    
    if (pDecCtl->decState != DEC_STOP)
    {
    	LOG_PrintError("vdec state is not stop!\n");
        return -1;
    } 

    if (pDecCtl->isCreateVdec)
    {
        ret = RK_MPI_VDEC_CreateChn(pDecCtl->vdecChn, &pDecCtl->vdecAttr);
        if (ret)
        {
            LOG_PrintError("Fail to RK_MPI_VDEC_CreateChn chn(%d) with ret=%d\n",
                            pDecCtl->vdecChn, ret);
            return -1;
        }

#ifdef DEC_CALL_BACK   

        enModId = RK_ID_VDEC;
        stDecChn.enModId = enModId;
        stDecChn.s32DevId = 0;
        stDecChn.s32ChnId = pDecCtl->vdecChn;
        ret = RK_MPI_SYS_RegisterOutCb(&stDecChn, DEC_PacketCb);
        if (ret) 
        {
            LOG_PrintError("Fail to RK_MPI_SYS_RegisterOutCbret=%d\n", ret);
            return -1;
        }

        LOG_PrintWarn("chn(%d) enCodecType(%d), RK_MPI_SYS_RegisterOutCb success\n", pDecCtl->vdecChn, pDecCtl->vdecAttr.enCodecType);
#endif        
    }

    pDecCtl->decState = DEC_START;

    pDecCtl->frameComeflg = 0; 

    return 0;
}

 /*******************************************************************************
  Function:     DEC_Start
  Description:  启动解码
  Input:        - pThiz: 视频解码接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int DEC_Start(struct VideoDecoder *pThiz)
{
    int ret = 0, result;
    DEC_ctl_t *pDecCtl;
    
    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pDecCtl = (DEC_ctl_t *)pThiz->priv;
    if (!pDecCtl)
    {
        LOG_PrintError("VideoDecoder isn't initialized\n");
        return -1;
    }

    pthread_mutex_lock(&videoCtl_g.decodeMutex[pDecCtl->vdecChn]);

    result = DEC_StartUnlock(pDecCtl);
    if (result)
    {
        LOG_PrintError("Fail to start encode channel %d!\n", pDecCtl->vdecChn);
        ret = -1;
        goto mutex_unlock;
    }

    LOG_PrintInfo("DEC_Start vdecChn:%d success,Format=%d\n",pDecCtl->vdecChn, pDecCtl->vdecAttr.enCodecType);

mutex_unlock:
    pthread_mutex_unlock(&videoCtl_g.decodeMutex[pDecCtl->vdecChn]);
    return ret;
}

/*******************************************************************************
  Function:     DEC_StopUnlock
  Description:  停止编码,不加锁
  Input:        - pDecCtl: 编码通道控制结构体 
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int DEC_StopUnlock(DEC_ctl_t *pDecCtl)
{
    int result;

	if (pDecCtl->decState == DEC_STOP)
	{
		LOG_PrintWarn("venc chn %d have been stoped!\n", pDecCtl->vdecChn);
		return 0;
	}

    pDecCtl->decState = DEC_STOP;

    if (pDecCtl->isCreateVdec)
    {
        //LOG_PrintWarn("DEC_StopUnlock test \n");
        result = RK_MPI_VDEC_DestroyChn(pDecCtl->vdecChn);
        if (result) 
        {
            LOG_PrintError("Fail to RK_MPI_VDEC_DestroyChn chn(%d) with ret=%d\n",
                            pDecCtl->vdecChn, result);
            return -1;
        }
        //LOG_PrintWarn("DEC_StopUnlock test \n");
    }
    
    usleep(100*1000); //停止后延迟一段时间，确保解码数据已经回调完毕

    DEC_DeinitList(pDecCtl);

    //LOG_PrintWarn("DEC_StopUnlock test \n");

    return 0;
}


/*******************************************************************************
  Function:     DEC_Stop
  Description:  停止解码
  Input:        - pThiz: 视频解码接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int DEC_Stop(struct VideoDecoder *pThiz)
{
    int ret = 0, result;
    DEC_ctl_t *pDecCtl;
    
    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }


    pDecCtl = (DEC_ctl_t *)pThiz->priv;
    if (!pDecCtl)
    {
        LOG_PrintError("VideoDecoder isn't initialized\n");
        return -1;
    }

    LOG_PrintWarn("pDecCtl->vdecChn:%d DEC_Stop enter \n", pDecCtl->vdecChn);

    
    pthread_mutex_lock(&videoCtl_g.decodeMutex[pDecCtl->vdecChn]);
    
    result = DEC_StopUnlock(pDecCtl);
    if (result)
    {
        LOG_PrintError("Fail to stop encode channel %d!\n", pDecCtl->vdecChn);
        ret = -1;
        goto mutex_unlock;
    }
    
    LOG_PrintWarn("pDecCtl->vdecChn:%d DEC_Stop success \n", pDecCtl->vdecChn);

    pDecCtl->frameComeflg = 1;

mutex_unlock:
    pthread_mutex_unlock(&videoCtl_g.decodeMutex[pDecCtl->vdecChn]);
    
    return ret;
}


static int DEC_PutYuvList(struct VideoDecoder *pThiz, uint32 height, uint32 weight, uint16 format,
								char** buffer, uint32 buffer_len)
{
	int ret = 0;
	DEC_ctl_t *pDecCtl;
	static long long cnt_tmp = 0;
	COMM_ListInfo_t *pListFrame = NULL;
	if (!pThiz)
	{
		LOG_PrintError("Input parameter is NULL\n");
		return -1;
	}

	pDecCtl = (DEC_ctl_t *)pThiz->priv;
	if (!pDecCtl)
	{
		LOG_PrintError("VideoDecoder isn't initialized\n");
		return -1;
	}

	STREAM_composeCtl_t* pComposeCtl = videoCtl_g.pComposeCtl;
	if (!pComposeCtl)
	{
		LOG_PrintInfo("pComposeCtl is NULL\n");
		return;
	}

	//uint8 buffer[640*180*3] = { 0 };
	int vdecChn = pDecCtl->vdecChn;
	//yuyv_to_nv12(packet->buffer, buffer, 640, 360, packet->length);

	RK_U32 mbSize = buffer_len;
	MEDIA_BUFFER mb = RK_MPI_MB_CreateBuffer(mbSize, RK_TRUE, 0);//RK_FALSE
	if (!mb)
	{
		LOG_PrintError("RK_MPI_MB_CreateBuffer failed !\n");
		ret = -1;
		return ret;
	}
	RK_MPI_MB_BeginCPUAccess(mb, RK_FALSE);
	if(format == RK_FORMAT_YCbCr_420_SP){
		memcpy(RK_MPI_MB_GetPtr(mb), buffer[0] , buffer_len / 3 * 2);
		memcpy(RK_MPI_MB_GetPtr(mb) + buffer_len / 3 * 2, buffer[1] , buffer_len / 6);
		memcpy(RK_MPI_MB_GetPtr(mb) + buffer_len / 6 * 5, buffer[2] , buffer_len / 6);
		format = RK_FORMAT_YCbCr_420_P;
		
	}else if(format == RK_FORMAT_YCbCr_422_P){
		memcpy(RK_MPI_MB_GetPtr(mb), buffer[0] , buffer_len / 2);
		memcpy(RK_MPI_MB_GetPtr(mb) + buffer_len / 2, buffer[1] , buffer_len / 4);
		memcpy(RK_MPI_MB_GetPtr(mb) + buffer_len / 4 * 3, buffer[2] , buffer_len / 4);
	}
	RK_MPI_MB_EndCPUAccess(mb, RK_FALSE);

	RK_MPI_MB_SetSize(mb, buffer_len);

	ENC_ImageRect_t stSrcRect = {0};
	ENC_ImageRect_t stDstRect = {0};

	stSrcRect.wid = weight;
	stSrcRect.hei = height;
	stSrcRect.wstride = weight;
	stSrcRect.hstride = height;
	static int count_times = 0;
#if 0
	count_times ++;
	if(count_times % 60 == 0)
	   LOG_PrintInfo("weight %d h : %d len : %d format :%x\n",weight, height, buffer_len, format);
#endif
	stDstRect.wid = 1920;
	stDstRect.hei = 1080;
	stDstRect.wstride = 1920;
	stDstRect.hstride = 1080;
#if 1
	pthread_mutex_lock(&pDecCtl->bufLock);
	if(!list_empty(&pDecCtl->emptyBuf))
	{
		pListFrame = list_first_entry(&pDecCtl->emptyBuf, COMM_ListInfo_t, list);
		list_del(&pListFrame->list);
		pthread_mutex_unlock(&pDecCtl->bufLock);

		//LOG_PrintInfo("emptyBuf list is get!,vdecChn=%d\n",vdecChn);
	}
	else
	{
		if (!list_empty(&pDecCtl->fullBuf)) {
			pListFrame = list_first_entry(&pDecCtl->fullBuf, COMM_ListInfo_t, list);
			list_del(&pListFrame->list);
			list_add_tail(&pListFrame->list, &pDecCtl->emptyBuf);
			pListFrame = list_first_entry(&pDecCtl->emptyBuf, COMM_ListInfo_t, list);
			list_del(&pListFrame->list);
			pthread_mutex_unlock(&pDecCtl->bufLock);
			//LOG_PrintWarn("1 vdecChn:%d emptyBuf list is empty!\n", vdecChn);
		}
		else 
		{
			pthread_mutex_unlock(&pDecCtl->bufLock);
			RK_MPI_MB_ReleaseBuffer(mb);
			//LOG_PrintWarn("2 vdecChn:%d emptyBuf list is empty!\n", vdecChn);
			return -1;
		} 
	}
#endif

	if(VI_ImageResizeRga(stSrcRect, stDstRect, mb, pListFrame->mdResizeBuf, format, RK_FORMAT_YCbCr_420_SP) < 0)
	{
		LOG_PrintError("VI_ImageResizeRga failed !\n"); 
		return -1;
	} 

	/*if(RK_MPI_MB_GetPtr(pListFrame->mdResizeBuf)){
		video_FILE_Write("/extern/gzm12.yuv", RK_MPI_MB_GetPtr(pListFrame->mdResizeBuf), 1920 * 540 * 3);
	} */
	pListFrame->stImageInfo = stDstRect;								
	pListFrame->streamType = USBTYPEAIN_STREAM;
	pListFrame->pts = vdo_get_time();
	//pListFrame->pts = 0;
	pthread_mutex_lock(&pDecCtl->bufLock);
	list_add_tail(&pListFrame->list, &pDecCtl->fullBuf);
	pthread_mutex_unlock(&pDecCtl->bufLock);
	
	pComposeCtl->newPts[vdecChn] = pListFrame->pts; //更新buf时间
	
	RK_MPI_MB_ReleaseBuffer(mb);
	
	return ret;
}

/// 填充帧数据到视频解码缓冲，非阻塞操作，如果底层缓冲已满，则返回错误。
/// 解码后的图像不一定立即显示，底层还需要进行帧率控制，直到解码后缓冲
/// 有足够空间，才可以填下次数据。
/// 
/// \param [in] thiz 视频解码接口指针
/// \param [in] packet 包数据信息，见VideoDecPacket结构。
/// \retval 0  写成功
/// \retval <0  写失败
static int DEC_PutPacket(struct VideoDecoder *pThiz, VideoDecPacket *packet)
{
    int ret = 0;
    DEC_ctl_t *pDecCtl;
    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pDecCtl = (DEC_ctl_t *)pThiz->priv;
    if (!pDecCtl)
    {
        LOG_PrintError("VideoDecoder isn't initialized\n");
        return -1;
    }

    pthread_mutex_lock(&videoCtl_g.decodeMutex[pDecCtl->vdecChn]);

    if(pDecCtl->decState == DEC_STOP)
    {
        LOG_PrintError("VideoDecoder decState stop, vdecChn:%d\n",pDecCtl->vdecChn);
        ret = -1;
        goto mutex_unlock;
    }
    //LOG_PrintWarn("vdecChn:%d, DEC_PutPacket start2\n",pDecCtl->vdecChn);

#if 0

    uint64_t timestamp = vdo_get_time();

    RK_U32 mbSize = 1920 * 1080 * 2;
    if (!mb)
    MEDIA_BUFFER mb = RK_MPI_MB_CreateBuffer(mbSize, RK_TRUE, 0);//RK_FALSE
    {
        LOG_PrintError("RK_MPI_MB_CreateBuffer failed !\n");
        ret = -1;
        goto mutex_unlock;
    }

    
    
    RK_MPI_MB_BeginCPUAccess(mb, RK_FALSE);
    memcpy(RK_MPI_MB_GetPtr(mb), packet->buffer, packet->length);
    RK_MPI_MB_EndCPUAccess(mb, RK_FALSE);

    RK_MPI_MB_SetSize(mb, packet->length);

    //RK_MPI_MB_SetTimestamp(mb, packet->pts);

    

    ret = RK_MPI_SYS_SendMediaBuffer(RK_ID_VDEC, pDecCtl->vdecChn, mb);
    
    
    
    //LOG_PrintError("RK_MPI_SYS_SendMediaBuffer success************\n");

    if(pDecCtl->vdecAttr.enCodecType == RK_CODEC_TYPE_JPEG)
    {
        while(test_dec_flg[pDecCtl->vdecChn] == 0)
        {
            usleep(2*1000);        
        }

        test_dec_flg[pDecCtl->vdecChn] = 0;

    #if 1
        uint64_t runtime = vdo_get_time() - timestamp;
        if(runtime > 30)
        LOG_PrintInfo("vdecChn:%d, RK_MPI_SYS_SendMediaBuffer runtime=%llu\n",pDecCtl->vdecChn,  runtime);
    #endif
    }

    
    RK_MPI_MB_ReleaseBuffer(mb);
    


   
#else       
    MEDIA_BUFFER decMd = NULL;

    if(pDecCtl->bufIndex == 0)
    {
        pDecCtl->bufIndex = 1;
        decMd = pDecCtl->decSendMd[0];        
    }
    else if(pDecCtl->bufIndex == 1)
    {        
        pDecCtl->bufIndex = 2;
        decMd = pDecCtl->decSendMd[1];                
    }
    else
    {        
        pDecCtl->bufIndex = 0;
        decMd = pDecCtl->decSendMd[2];                
    }
    
    RK_MPI_MB_BeginCPUAccess(decMd, RK_FALSE);
    memcpy(RK_MPI_MB_GetPtr(decMd), packet->buffer, packet->length);
    RK_MPI_MB_EndCPUAccess(decMd, RK_FALSE);

    RK_MPI_MB_SetSize(decMd, packet->length);   

    RK_MPI_MB_SetTimestamp(decMd, packet->pts);
    
    ret = RK_MPI_SYS_SendMediaBuffer(RK_ID_VDEC, pDecCtl->vdecChn, decMd);   
    if (ret) 
    {
        LOG_PrintError("Fail to RK_MPI_SYS_SendMediaBuffer RK_ID_VDEC with %d\n", ret);
    }

    uint64_t timestamp = vdo_get_time();

    if(pDecCtl->vdecAttr.enCodecType == RK_CODEC_TYPE_JPEG)
    {   
        pthread_mutex_lock(&pDecCtl->frameLock);  
        while(pDecCtl->frameComeflg == 0)
        {
            struct timespec timeout;
            clock_gettime(CLOCK_REALTIME, &timeout);
            timeout.tv_nsec += 100000000; // 100 毫秒
            if (timeout.tv_nsec >= 1000000000) {
                timeout.tv_nsec -= 1000000000;
                timeout.tv_sec++;
            }

            if(pthread_cond_timedwait(&pDecCtl->frameCond, &pDecCtl->frameLock, &timeout) != 0){
                LOG_PrintError("DEC_PutPacket   wait frame decoder  timeout\n");
                break;
            }    
        }

        pDecCtl->frameComeflg = 0;
        pthread_mutex_unlock(&pDecCtl->frameLock);  
    }

#endif

#if 0
    if(cnt_tmp++ % 30 == 0  && pDecCtl->vdecChn == 15)
    {
        LOG_PrintWarn("vdecChn:%d, RK_MPI_SYS_SendMediaBuffer success, length=%d\n",pDecCtl->vdecChn, packet->length);
        
        //uint64_t timestamp2 = vdo_get_time();
        //LOG_PrintInfo("vdecChn:%d, RK_MPI_SYS_SendMediaBuffer runtime=%llu\n", pDecCtl->vdecChn, (timestamp2 - timestamp));

        //video_FILE_Write("/nfsroot/wyg/vdecin.h264", packet->buffer, packet->length);
    }
#endif

mutex_unlock:
    pthread_mutex_unlock(&videoCtl_g.decodeMutex[pDecCtl->vdecChn]);   

    return ret;
}


/// 清空解码后图像缓冲，被阻塞的putPacket将会立即返回。
/// 
/// \param [in] thiz 视频解码接口指针
/// \retval 0  清空成功
/// \retval <0  清空失败
static int DEC_Flush(struct VideoDecoder *thiz)
{
    return 0;
}


/// 检查解码后缓冲是否为空，即图像是否已经被全部呈现。
/// 
/// \param [in] thiz 视频解码接口指针
/// \retval 0  非空
/// \retval 1  已空
/// \return <0 检查出错
static int DEC_Empty(struct VideoDecoder *thiz)
{
    return 0;
}



/// 得到视频画面的实际分辨率大小
/// 
/// \param [in] thiz 视频解码接口指针
/// \param [in] size 存放分辨率。
/// \retval 0  获取成功
/// \retval <0  获取失败
static int DEC_GetSize(struct VideoDecoder *thiz, Size *size)
{
    return 0;
}


/// 设置回放的时间戳，已经解码后的图像如果其时间戳小于设置的时间戳，应立即输出。
/// 
/// \param [in] thiz 视频解码接口指针
/// \param [in] pts 参考时间戳。
/// \retval 0  设置成功
/// \retval <0  设置失败    
static int DEC_SetPts(struct VideoDecoder *thiz, uint64 pts)
{
    return 0;
}


/// 将前一帧已经解码的数据再次压缩成图片
/// 
/// \param [in] thiz 视频解码接口指针
/// \param [in] param 抓图参数
/// \retval 0  压缩成功
/// \retval <0  压缩失败    
static int DEC_Snapshot(struct VideoDecoder *thiz, VideoDecSnapshotParam*  param)
{
    return 0;
}


/*******************************************************************************
  Function:     DEC_GetChipId
  Description:  得到解码器所在的芯片ID
  Input:        - pThiz: 视频解码接口指针
  Output:       无
  Return:       >=0 芯片ID，由库里面统一分配，不同的芯片有唯一的编号。
                    芯片号在创建解码通道的时候得到
                <0: 操作失败
  Others:       无
*******************************************************************************/
static int DEC_GetChipId(struct VideoDecoder *pThiz)
{
    return videoCtl_g.cpuType;
}

/*******************************************************************************
  Function:     DEC_GetChipCaps
  Description:  获得芯片的解码能力
  Input:        - pThiz: 视频解码接口指针
  Output:       - pDecChipCaps: 芯片能力结构VideoEncChipCaps指针
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int DEC_GetChipCaps(struct VideoDecoder *pThiz, 
                           VideoDecChipsCaps *pDecChipCaps)
{
    DEC_ctl_t *pDecCtl;
    
    if ((NULL == pThiz) || (NULL == pDecChipCaps))
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pDecCtl = (DEC_ctl_t *)pThiz->priv;
    if (!pDecCtl)
    {
        LOG_PrintError("VideoDecoder isn't initialized\n");
        return -1;
    }

    switch (videoCtl_g.cpuType)
    {            
        case SYS_CPU_HI3559AV100:
            pDecChipCaps->ladenBitrate
                = (7680*4320*30+1920*1080*30)/64;
            break;   
        case SYS_CPU_HI3519AV100:
            pDecChipCaps->ladenBitrate
                = (3840*2160*60+1280*720*30)/64;
            break;    
		case SYS_CPU_HI3516CV500:
		case SYS_CPU_HI3516DV300:
            pDecChipCaps->ladenBitrate
                = (1920*1080*30+720*480*30+360*240*30)/64;
            break;   
		case SYS_CPU_HI3516EV200:
		case SYS_CPU_HI3518EV300:
			pDecChipCaps->ladenBitrate
				= (2048*1536*20+720*576*20)/64;
			break; 
		case SYS_CPU_HI3516EV300:
			pDecChipCaps->ladenBitrate
				= (2048*1536*30+720*576*30)/64;
			break;      
        default:
            LOG_PrintError("cpu type %d is invalid!\n", videoCtl_g.cpuType);
            return -1;
    }
    
    return 0;
}

/*******************************************************************************
  Function:     DEC_GetCaps
  Description:  得到视频解码设备能力
  Input:        - pThiz: 视频解码接口指针
  Output:       - pDecCaps: 解码能力结构VideoEncCaps指针
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int DEC_GetCaps(struct VideoDecoder *pThiz, VideoDecCaps *pDecCaps)
{
    DEC_ctl_t *pDecCtl;
    
    if ((NULL == pThiz) || (NULL == pDecCaps))
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pDecCtl = (DEC_ctl_t *)pThiz->priv;
    if (!pDecCtl)
    {
        LOG_PrintError("VideoDecoder isn't initialized\n");
        return -1;
    } 
    
    return 0;
}

/*******************************************************************************
  Function:     DEC_SetStreamDisplayChn
  Description:  设置流的显示通道
  Input:        - pThiz: 视频解码接口指针
  Output:       - channel: 显示通道
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
/*
static int DEC_SetStreamDisplayChn(struct VideoDecoder *pThiz, int channel)
{

    DEC_ctl_t *pDecCtl;
    
    if (NULL == pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pDecCtl = (DEC_ctl_t *)pThiz->priv;
    if (!pDecCtl)
    {
        LOG_PrintError("VideoDecoder isn't initialized\n");
        return -1;
    } 

    pDecCtl->displayChn = channel;
   
    return 0;
}
*/


 /// 创建视频解码接口。创建成功后，如果芯片资源限制，不一定可以正常解码。
 /// 
 /// \param [in] dest 视频解码接口描述结构VideoDecDesc指针
 /// \param [out] videoDecoder 视频解码接口指针的指针
 /// \retval <0 创建失败
 /// \retval 0 创建成功
 int PAL_API createVideoDecoder(VideoDecDesc *pDecDesc, VideoDecoder **ppVideoDecoder)
 {
    int ret = 0, result = 0;

    VideoDecoder *pVideoDecoder = NULL;

    DEC_ctl_t *pDecCtl = NULL;
    
    VIDEO_resolution_t resolution = videoCtl_g.resolution;

    unsigned int descChannel = 0;

    if ((NULL == pDecDesc) || (NULL == ppVideoDecoder))
    {
        LOG_PrintError("Parameter is NULL!\n");
        return -1;
    }

    descChannel = pDecDesc->channel;
    if(descChannel >= VDEC_MAX_CHN_NUM)
    {
        LOG_PrintError("descChannel over maxnum !\n");
        return -1;
    }

    pthread_mutex_lock(&videoCtl_g.decodeMutex[descChannel]);
    
    pDecCtl = videoCtl_g.pDecCtls[descChannel];
    if (pDecCtl)
    {
        LOG_PrintInfo("video decoder has already been created,"
                       "dest = %d\n", 
                       pDecDesc->channel);
        pDecCtl->refCount++;
        *ppVideoDecoder = &pDecCtl->videoDecoder;
        goto mutex_unlock;
    }

    pDecCtl = (DEC_ctl_t *)malloc(sizeof(DEC_ctl_t));
    if (!pDecCtl)
    {
        LOG_PrintError("There is no enough memory to allocate VideoDecoder!\n");
        ret = -1;
        goto mutex_unlock;
    }
    memset(pDecCtl, 0, sizeof(DEC_ctl_t));

    pDecCtl->refCount++;
    pDecCtl->decState = DEC_STOP; 
    pDecCtl->vdecChn = descChannel;
    pDecCtl->isCreateVdec = 1;
    pDecCtl->bufIndex = 0;

    MB_IMAGE_INFO_S stImageInfo = {0};
    stImageInfo.enImgType = IMAGE_TYPE_NV12;
    stImageInfo.u32Width = DEC_WIDTH;
    stImageInfo.u32Height = DEC_HEIGHT;
    stImageInfo.u32HorStride = stImageInfo.u32Width;
    stImageInfo.u32VerStride = stImageInfo.u32Height;

    RK_U32 mbSize = 1920 * 1080 * 2;
    for(int i = 0; i < 3; ++i)
    {
        //pDecCtl->decSendMd[i] = RK_MPI_MB_CreateImageBuffer(&stImageInfo, RK_TRUE, 0);
        pDecCtl->decSendMd[i] = RK_MPI_MB_CreateBuffer(mbSize, RK_TRUE, 0);
        if (!pDecCtl->decSendMd[i])
        {
            LOG_PrintError("RK_MPI_MB_CreateImageBuffer failed !\n");
            ret = -1;
            goto free_ctl;
        }
    }

    pDecCtl->maxBufLen = DEC_WIDTH * DEC_HEIGHT *200/100; //考虑虚宽和虚高和h265
    INIT_LIST_HEAD(&pDecCtl->emptyBuf);
    INIT_LIST_HEAD(&pDecCtl->fullBuf);
    pthread_mutex_init(&pDecCtl->bufLock, NULL);
    pthread_mutex_init(&pDecCtl->frameLock, NULL);
    pthread_cond_init(&pDecCtl->frameCond, NULL);

    for (int i = 0; i < 5; i++)
    {
        pDecCtl->listBuf[i].mdResizeBuf = RK_MPI_MB_CreateBuffer(pDecCtl->maxBufLen, RK_TRUE, 0);
        if (!pDecCtl->listBuf[i].mdResizeBuf)
        {
            LOG_PrintError("Fail to malloc!\n");
            ret = -1;
            RK_MPI_MB_ReleaseBuffer(pDecCtl->decSendMd[0]);
            RK_MPI_MB_ReleaseBuffer(pDecCtl->decSendMd[1]);
            RK_MPI_MB_ReleaseBuffer(pDecCtl->decSendMd[2]);
            goto free_ctl;
        }
	    list_add_tail(&pDecCtl->listBuf[i].list, &pDecCtl->emptyBuf);
	}
	//LOG_PrintError("pDecCtl->maxBufLen: %d\n", pDecCtl->maxBufLen);

    videoCtl_g.pDecCtls[descChannel] = pDecCtl;
    videoCtl_g.createDecNum++;


    pVideoDecoder = &pDecCtl->videoDecoder;
    pVideoDecoder->priv = pDecCtl;
    pVideoDecoder->addRef = DEC_AddRef;
    pVideoDecoder->release = DEC_Release;
    pVideoDecoder->getChipId = DEC_GetChipId;
    pVideoDecoder->getChipCaps = DEC_GetChipCaps;
    pVideoDecoder->getCaps = DEC_GetCaps;
    pVideoDecoder->start = DEC_Start;
    pVideoDecoder->stop = DEC_Stop;
    pVideoDecoder->empty = DEC_Empty;
    pVideoDecoder->flush = DEC_Flush;
    pVideoDecoder->getSize = DEC_GetSize;
    pVideoDecoder->putPacket = DEC_PutPacket;
	pVideoDecoder->putYuvList = DEC_PutYuvList;
    pVideoDecoder->setFormat = DEC_SetFormat;
    pVideoDecoder->setPts = DEC_SetPts;
    pVideoDecoder->snapshot = DEC_Snapshot;
    //pVideoDecoder->setStreamDisplayChn =DEC_SetStreamDisplayChn;


    *ppVideoDecoder = &pDecCtl->videoDecoder;

#ifndef DEC_CALL_BACK          
    /* create data recv thread */
    ret = pthread_create(&decGetDataThd, NULL, DEC_GetDataThd, pDecCtl);
    if(ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        ret = -1;
    }
#endif
     
    LOG_PrintInfo("Create videoDecoder::%d successfully!\n",descChannel);
    goto mutex_unlock;
    
free_ctl: 
    free(pDecCtl);
    
mutex_unlock:
    pthread_mutex_unlock(&videoCtl_g.decodeMutex[descChannel]);
    return ret;
 }

